package com.srmt.user.feishu;

import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.stream.JsonReader;
import com.lark.oapi.Client;
import com.lark.oapi.core.enums.AppType;
import com.lark.oapi.core.enums.BaseUrlEnum;
import com.lark.oapi.service.contact.v3.model.GetUserReq;
import com.lark.oapi.service.contact.v3.model.GetUserResp;
import com.lark.oapi.service.contact.v3.model.BatchGetIdUserReq;
import com.lark.oapi.service.contact.v3.model.BatchGetIdUserResp;
import com.lark.oapi.service.contact.v3.model.BatchGetIdUserReqBody;
import com.lark.oapi.service.contact.v3.model.UserContactInfo;

import com.lark.oapi.service.im.v1.enums.UserIdTypeEnum;
import com.srmt.user.api.UserIdResolver;
import com.srmt.common.config.ApplicationConfig;
import com.srmt.user.exception.UserServiceException;
import com.srmt.user.exception.UserNotFoundException;
import com.srmt.user.exception.InvalidIdentifierException;
import com.srmt.user.model.IdentifierType;

import jdk.nashorn.internal.parser.JSONParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/**
 * 飞书用户ID解析器实现
 * 
 * @author SRMT Development Team
 * @since 1.0.0
 */
public class FeishuUserIdResolver implements UserIdResolver {

    private static final Logger logger = LoggerFactory.getLogger(FeishuUserIdResolver.class);

    /**
     * 邮箱格式验证正则表达式
     * 严格验证邮箱格式：用户名@域名.顶级域名
     */
    private static final Pattern EMAIL_PATTERN = Pattern.compile(
        "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"
    );

    /**
     * 电话号码格式验证正则表达式
     * 允许数字、+、-、空格、括号
     */
    private static final Pattern PHONE_PATTERN = Pattern.compile(
        "^[\\d\\s+\\-()]+$"
    );

    private final ApplicationConfig applicationConfig;
    private final Client client;
    private final Map<String, CachedUser> identifierCache;
    
    /**
     * 缓存的用户信息
     */
    private static class CachedUser {
        final String userId;
        final long expireTime;
        
        CachedUser(String userId, long ttlMillis) {
            this.userId = userId;
            this.expireTime = System.currentTimeMillis() + ttlMillis;
        }
        
        boolean isExpired() {
            return System.currentTimeMillis() > expireTime;
        }
    }
    
    /**
     * 构造函数
     * 
     * @param applicationConfig 应用配置对象
     */
    public FeishuUserIdResolver(ApplicationConfig applicationConfig) {
        if (applicationConfig == null) {
            throw new IllegalArgumentException("应用配置对象不能为null");
        }
        
        applicationConfig.validate();
        this.applicationConfig = applicationConfig;
        
        this.client = initializeClient();

        // 初始化统一缓存（支持电话和邮箱）
        if (applicationConfig.getService().getCache().isEnabled()) {
            this.identifierCache = new ConcurrentHashMap<>(applicationConfig.getService().getCache().getSize());
        } else {
            this.identifierCache = null;
        }

        logger.info("飞书用户ID解析器初始化成功");
    }
    
    /**
     * 初始化飞书客户端
     */
    private Client initializeClient() {
        logger.debug("使用应用ID初始化飞书客户端: {}", applicationConfig.getFeishu().getAppId());
        
        Client.Builder builder = Client.newBuilder(applicationConfig.getFeishu().getAppId(), applicationConfig.getFeishu().getAppSecret());
        
        // 设置应用类型，默认为SELF_BUILT
        builder.appType(AppType.SELF_BUILT);
        
        // 设置基础URL
        String baseUrl = applicationConfig.getFeishu().getBaseUrl();
        if (baseUrl != null && !baseUrl.isEmpty()) {
            if (baseUrl.contains("feishu")) {
                builder.openBaseUrl(BaseUrlEnum.FeiShu);
            } else if (baseUrl.contains("lark")) {
                builder.openBaseUrl(BaseUrlEnum.LarkSuite);
            }
        }
        
        // 设置超时
        if (applicationConfig.getService().getTimeout() > 0) {
            builder.requestTimeout(applicationConfig.getService().getTimeout(), TimeUnit.MILLISECONDS);
        }
        builder.logReqAtDebug(true);
        
        return builder.build();
    }
    
    @Override
    public String getUserIdByPhone(String phoneNumber) throws UserServiceException {
        if (phoneNumber == null || phoneNumber.trim().isEmpty()) {
            throw new IllegalArgumentException("电话号码不能为null或空");
        }
        
        // 格式化电话号码
        String formattedPhone = formatPhoneNumber(phoneNumber);
        logger.debug("通过电话号码查找用户: {}", formattedPhone);
        
        // 检查缓存
        if (applicationConfig.getService().getCache().isEnabled() && identifierCache != null) {
            CachedUser cached = identifierCache.get(formattedPhone);
            if (cached != null && !cached.isExpired()) {
                logger.debug("电话号码缓存命中: {}", formattedPhone);
                return cached.userId;
            }
        }
        
        try {
            // 使用批量ID查询接口
            BatchGetIdUserReq req = BatchGetIdUserReq.newBuilder()
                    .userIdType(UserIdTypeEnum.USER_ID.getValue())
                    .batchGetIdUserReqBody(
                        BatchGetIdUserReqBody.newBuilder()
                            .mobiles(new String[]{formattedPhone})
                            .includeResigned(false)
                            .build()
                    )
                    .build();
            logger.info("通过API查询用户,手机号: {}", formattedPhone);
            logger.info("请求: {}", new GsonBuilder().create().toJson(req));
            BatchGetIdUserResp resp = client.contact().v3().user().batchGetId(req);
            logger.info("响应: {}", new GsonBuilder().create().toJson(resp));
            
            if (!resp.success()) {
                logger.error("通过手机号查询用户失败: code={}, msg={}", 
                    resp.getCode(), resp.getMsg());
                throw new UserServiceException(String.format("查询用户失败: %s (错误码: %d)", 
                    resp.getMsg(), resp.getCode()));
            }
            
            if (resp.getData() == null || resp.getData().getUserList() == null || 
                resp.getData().getUserList().length == 0) {
                logger.info("未找到手机号为{}的用户", formattedPhone);
                return null;
            }
            
            UserContactInfo userInfo = resp.getData().getUserList()[0];
            String userId = userInfo.getUserId();
            
            // 缓存结果
            if (applicationConfig.getService().getCache().isEnabled() && identifierCache != null) {
                long ttlMillis = applicationConfig.getService().getCache().getTtlMinutes() * 60 * 1000L;
                identifierCache.put(formattedPhone, new CachedUser(userId, ttlMillis));

                // 清理过期缓存
                cleanExpiredCache();
            }
            
            logger.info("通过手机号{}找到用户{}", formattedPhone, userId);
            return userId;
            
        } catch (Exception e) {
            logger.error("错误 querying user by phone: " + formattedPhone, e);
            throw new UserServiceException("通过手机号查询用户失败", e);
        }
    }
    
    
    /**
     * 格式化电话号码
     *
     * @param phoneNumber 原始电话号码
     * @return 格式化后的电话号码
     */
    private String formatPhoneNumber(String phoneNumber) {
        // 移除所有空格、短横线等
        String cleaned = phoneNumber.replaceAll("[\\s\\-()]", "");

        // 如果没有国家码，添加中国区号
        if (!cleaned.startsWith("+")) {
            cleaned = "+86" + cleaned;
        }

        return cleaned;
    }

    /**
     * 识别标识符类型
     *
     * @param identifier 标识符（电话或邮箱）
     * @return 标识符类型
     */
    private IdentifierType detectIdentifierType(String identifier) {
        if (identifier == null || identifier.trim().isEmpty()) {
            return IdentifierType.UNKNOWN;
        }

        String trimmed = identifier.trim();

        // 检查是否包含@符号，优先识别为邮箱
        if (trimmed.contains("@")) {
            return isValidEmail(trimmed) ? IdentifierType.EMAIL : IdentifierType.UNKNOWN;
        }

        // 检查是否符合电话号码格式（数字、+、-、空格、括号）
        if (PHONE_PATTERN.matcher(trimmed).matches()) {
            return IdentifierType.PHONE;
        }

        return IdentifierType.UNKNOWN;
    }

    /**
     * 严格验证邮箱格式
     *
     * @param email 邮箱地址
     * @return 是否为有效邮箱格式
     */
    private boolean isValidEmail(String email) {
        if (email == null || email.trim().isEmpty()) {
            return false;
        }
        return EMAIL_PATTERN.matcher(email.trim()).matches();
    }

    /**
     * 格式化邮箱地址
     * 规范化邮箱格式：去除首尾空格，转换为小写
     *
     * @param email 原始邮箱地址
     * @return 格式化后的邮箱地址
     */
    private String formatEmail(String email) {
        return email.trim().toLowerCase();
    }

    /**
     * 根据标识符类型进行格式化
     *
     * @param identifier 原始标识符
     * @param type 标识符类型
     * @return 格式化后的标识符
     * @throws InvalidIdentifierException 标识符格式无效时抛出
     */
    private String formatIdentifier(String identifier, IdentifierType type) throws InvalidIdentifierException {
        switch (type) {
            case PHONE:
                return formatPhoneNumber(identifier);
            case EMAIL:
                if (!isValidEmail(identifier)) {
                    throw new InvalidIdentifierException(identifier, "邮箱");
                }
                return formatEmail(identifier);
            case UNKNOWN:
            default:
                throw new InvalidIdentifierException(
                    "无法识别标识符类型: " + identifier,
                    identifier,
                    "UNKNOWN"
                );
        }
    }

    /**
     * 清理过期缓存
     */
    private void cleanExpiredCache() {
        if (identifierCache == null || identifierCache.size() < applicationConfig.getService().getCache().getSize() * 0.8) {
            return;
        }

        identifierCache.entrySet().removeIf(entry -> entry.getValue().isExpired());
    }
    
    @Override
    public Map<String, String> getUserIdsByPhones(List<String> phoneNumbers) throws UserServiceException {
        if (phoneNumbers == null || phoneNumbers.isEmpty()) {
            return new HashMap<>();
        }
        
        Map<String, String> result = new HashMap<>();
        List<String> phonesToQuery = new ArrayList<>();
        Map<String, String> formattedToOriginalMap = new HashMap<>();
        
        // 先检查缓存，收集需要查询的电话号码
        for (String phone : phoneNumbers) {
            if (phone == null || phone.trim().isEmpty()) {
                continue;
            }
            
            String formattedPhone = formatPhoneNumber(phone);
            formattedToOriginalMap.put(formattedPhone, phone);

            // 检查缓存
            if (applicationConfig.getService().getCache().isEnabled() && identifierCache != null) {
                CachedUser cached = identifierCache.get(formattedPhone);
                if (cached != null && !cached.isExpired()) {
                    logger.debug("电话号码缓存命中: {}", formattedPhone);
                    result.put(phone, cached.userId);
                    continue;
                }
            }

            phonesToQuery.add(formattedPhone);
        }
        
        // 如果没有需要查询的，直接返回缓存结果
        if (phonesToQuery.isEmpty()) {
            logger.debug("缓存中找到所有{}个手机号", result.size());
            return result;
        }
        
        logger.debug("批量查询{}个手机号", phonesToQuery.size());
        
        try {
            // 飞书API限制：批量查询最多支持50个电话号码
            final int BATCH_SIZE = 50;
            for (int i = 0; i < phonesToQuery.size(); i += BATCH_SIZE) {
                List<String> batch = phonesToQuery.subList(i, 
                    Math.min(i + BATCH_SIZE, phonesToQuery.size()));
                
                // 批量查询用户
                BatchGetIdUserReq req = BatchGetIdUserReq.newBuilder()
                        .userIdType(UserIdTypeEnum.USER_ID.getValue())
                        .batchGetIdUserReqBody(
                            BatchGetIdUserReqBody.newBuilder()
                                .mobiles(batch.toArray(new String[0]))
                                .includeResigned(false)
                                .build()
                        )
                        .build();
                
                BatchGetIdUserResp resp = client.contact().v3().user().batchGetId(req);
                
                if (!resp.success()) {
                    logger.error("批量查询用户失败: code={}, msg={}", 
                        resp.getCode(), resp.getMsg());
                    throw new UserServiceException(String.format("批量查询用户失败: %s (错误码: %d)", 
                        resp.getMsg(), resp.getCode()));
                }
                
                // 处理查询结果
                if (resp.getData() != null && resp.getData().getUserList() != null) {
                    for (UserContactInfo userInfo : resp.getData().getUserList()) {
                        if (userInfo.getUserId() != null && userInfo.getMobile() != null) {
                            String formattedPhone = userInfo.getMobile();
                            String originalPhone = formattedToOriginalMap.get(formattedPhone);
                            if (originalPhone != null) {
                                result.put(originalPhone, userInfo.getUserId());

                                // 缓存结果
                                if (applicationConfig.getService().getCache().isEnabled() && identifierCache != null) {
                                    long ttlMillis = applicationConfig.getService().getCache().getTtlMinutes() * 60 * 1000L;
                                    identifierCache.put(formattedPhone, new CachedUser(userInfo.getUserId(), ttlMillis));
                                }
                            }
                        }
                    }
                }
            }

            // 清理过期缓存
            if (applicationConfig.getService().getCache().isEnabled() && identifierCache != null) {
                cleanExpiredCache();
            }

            logger.info("批量查询完成: 从{}个手机号中找到{}个用户",
                result.size(), phoneNumbers.size());
            return result;
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new UserServiceException("批量查询被中断", e);
        } catch (Exception e) {
            logger.error("批量查询用户时出现错误", e);
            throw new UserServiceException("批量查询用户失败", e);
        }
    }

    @Override
    public String getUserIdByPhoneOrEmail(String identifier) throws UserServiceException {
        if (identifier == null || identifier.trim().isEmpty()) {
            throw new IllegalArgumentException("标识符不能为null或empty");
        }

        // 识别标识符类型
        IdentifierType type = detectIdentifierType(identifier);
        logger.debug("检测到标识符类型: {},值: {}", type, identifier);

        // 格式化标识符
        String formattedIdentifier = formatIdentifier(identifier, type);
        logger.debug("通过{}查找用户: {}", type, formattedIdentifier);

        // 检查缓存
        if (applicationConfig.getService().getCache().isEnabled() && identifierCache != null) {
            CachedUser cached = identifierCache.get(formattedIdentifier);
            if (cached != null && !cached.isExpired()) {
                logger.debug("缓存命中,{}: {}", type, formattedIdentifier);
                return cached.userId;
            }
        }

        try {
            // 根据类型调用不同的API
            BatchGetIdUserReqBody.Builder bodyBuilder = BatchGetIdUserReqBody.newBuilder()
                    .includeResigned(false);

            if (type == IdentifierType.PHONE) {
                bodyBuilder.mobiles(new String[]{formattedIdentifier});
            } else if (type == IdentifierType.EMAIL) {
                bodyBuilder.emails(new String[]{formattedIdentifier});
            }

            BatchGetIdUserReq req = BatchGetIdUserReq.newBuilder()
                    .userIdType(UserIdTypeEnum.USER_ID.getValue())
                    .batchGetIdUserReqBody(bodyBuilder.build())
                    .build();

            BatchGetIdUserResp resp = client.contact().v3().user().batchGetId(req);

            if (!resp.success()) {
                logger.error("通过{}: code={}, msg={}",
                    type, resp.getCode(), resp.getMsg());
                throw new UserServiceException(String.format("查询用户失败: %s (错误码: %d)",
                    resp.getMsg(), resp.getCode()));
            }

            if (resp.getData() == null || resp.getData().getUserList() == null ||
                resp.getData().getUserList().length == 0) {
                logger.info("未找到{}为{}的用户", type, formattedIdentifier);
                return null;
            }

            UserContactInfo userInfo = resp.getData().getUserList()[0];
            String userId = userInfo.getUserId();

            // 缓存结果
            if (applicationConfig.getService().getCache().isEnabled() && identifierCache != null) {
                long ttlMillis = applicationConfig.getService().getCache().getTtlMinutes() * 60 * 1000L;
                identifierCache.put(formattedIdentifier, new CachedUser(userId, ttlMillis));

                // 清理过期缓存
                cleanExpiredCache();
            }

            logger.info("通过{}{}找到用户{}", type, formattedIdentifier, userId);
            return userId;

        } catch (Exception e) {
            logger.error("错误 querying user by {}: " + formattedIdentifier, type, e);
            throw new UserServiceException("通过" + type, e);
        }
    }

    @Override
    public Map<String, String> getUserIdsByPhoneOrEmail(List<String> identifiers) throws UserServiceException {
        if (identifiers == null || identifiers.isEmpty()) {
            return new HashMap<>();
        }

        Map<String, String> result = new HashMap<>();
        List<String> phonesToQuery = new ArrayList<>();
        List<String> emailsToQuery = new ArrayList<>();
        Map<String, String> formattedToOriginalMap = new HashMap<>();

        // 分类并检查缓存
        for (String identifier : identifiers) {
            if (identifier == null || identifier.trim().isEmpty()) {
                continue;
            }

            // 识别类型
            IdentifierType type = detectIdentifierType(identifier);
            if (type == IdentifierType.UNKNOWN) {
                logger.warn("跳过未知的标识符类型: {}", identifier);
                continue;
            }

            // 格式化
            String formattedIdentifier;
            try {
                formattedIdentifier = formatIdentifier(identifier, type);
            } catch (InvalidIdentifierException e) {
                logger.warn("跳过无效的标识符: {}", identifier);
                continue;
            }

            formattedToOriginalMap.put(formattedIdentifier, identifier);

            // 检查缓存
            if (applicationConfig.getService().getCache().isEnabled() && identifierCache != null) {
                CachedUser cached = identifierCache.get(formattedIdentifier);
                if (cached != null && !cached.isExpired()) {
                    logger.debug("缓存命中,{}: {}", type, formattedIdentifier);
                    result.put(identifier, cached.userId);
                    continue;
                }
            }

            // 分类待查询的标识符
            if (type == IdentifierType.PHONE) {
                phonesToQuery.add(formattedIdentifier);
            } else if (type == IdentifierType.EMAIL) {
                emailsToQuery.add(formattedIdentifier);
            }
        }

        // 如果没有需要查询的，直接返回缓存结果
        if (phonesToQuery.isEmpty() && emailsToQuery.isEmpty()) {
            logger.debug("缓存中找到所有{}个标识符", result.size());
            return result;
        }

        logger.debug("批量查询{}个手机号和{}个邮箱",
            phonesToQuery.size(), emailsToQuery.size());

        try {
            // 批量查询电话号码
            if (!phonesToQuery.isEmpty()) {
                queryBatch(phonesToQuery, IdentifierType.PHONE, formattedToOriginalMap, result);
            }

            // 批量查询邮箱
            if (!emailsToQuery.isEmpty()) {
                queryBatch(emailsToQuery, IdentifierType.EMAIL, formattedToOriginalMap, result);
            }

            // 清理过期缓存
            if (applicationConfig.getService().getCache().isEnabled() && identifierCache != null) {
                cleanExpiredCache();
            }

            logger.info("批量查询完成: 从{}个标识符中找到{}个用户",
                result.size(), identifiers.size());
            return result;

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new UserServiceException("批量查询被中断", e);
        } catch (Exception e) {
            logger.error("批量查询用户时出现错误", e);
            throw new UserServiceException("批量查询用户失败", e);
        }
    }

    /**
     * 批量查询指定类型的标识符
     *
     * @param identifiersToQuery 待查询的标识符列表
     * @param type 标识符类型
     * @param formattedToOriginalMap 格式化标识符到原始标识符的映射
     * @param result 结果Map，会在此方法中更新
     * @throws Exception 查询失败时抛出
     */
    private void queryBatch(List<String> identifiersToQuery, IdentifierType type,
                            Map<String, String> formattedToOriginalMap,
                            Map<String, String> result) throws Exception {
        final int BATCH_SIZE = 50;

        for (int i = 0; i < identifiersToQuery.size(); i += BATCH_SIZE) {
            List<String> batch = identifiersToQuery.subList(i,
                Math.min(i + BATCH_SIZE, identifiersToQuery.size()));

            // 构建请求
            BatchGetIdUserReqBody.Builder bodyBuilder = BatchGetIdUserReqBody.newBuilder()
                    .includeResigned(false);

            if (type == IdentifierType.PHONE) {
                bodyBuilder.mobiles(batch.toArray(new String[0]));
            } else if (type == IdentifierType.EMAIL) {
                bodyBuilder.emails(batch.toArray(new String[0]));
            }

            BatchGetIdUserReq req = BatchGetIdUserReq.newBuilder()
                    .userIdType(UserIdTypeEnum.USER_ID.getValue())
                    .batchGetIdUserReqBody(bodyBuilder.build())
                    .build();

            BatchGetIdUserResp resp = client.contact().v3().user().batchGetId(req);

            if (!resp.success()) {
                logger.error("批量查询用户失败 by {}: code={}, msg={}",
                    type, resp.getCode(), resp.getMsg());
                throw new UserServiceException(String.format("批量查询用户失败: %s (code: %d)",
                    resp.getMsg(), resp.getCode()));
            }

            // 处理查询结果
            if (resp.getData() != null && resp.getData().getUserList() != null) {
                for (UserContactInfo userInfo : resp.getData().getUserList()) {
                    if (userInfo.getUserId() == null) {
                        continue;
                    }

                    // 根据类型获取对应的标识符
                    String formattedIdentifier = null;
                    if (type == IdentifierType.PHONE && userInfo.getMobile() != null) {
                        formattedIdentifier = userInfo.getMobile();
                    } else if (type == IdentifierType.EMAIL && userInfo.getEmail() != null) {
                        formattedIdentifier = userInfo.getEmail();
                    }

                    if (formattedIdentifier != null) {
                        String originalIdentifier = formattedToOriginalMap.get(formattedIdentifier);
                        if (originalIdentifier != null) {
                            result.put(originalIdentifier, userInfo.getUserId());

                            // 缓存结果
                            if (applicationConfig.getService().getCache().isEnabled() && identifierCache != null) {
                                long ttlMillis = applicationConfig.getService().getCache().getTtlMinutes() * 60 * 1000L;
                                identifierCache.put(formattedIdentifier, new CachedUser(userInfo.getUserId(), ttlMillis));
                            }
                        }
                    }
                }
            }
        }
    }
}